'''
This file is part of DopplerShift.

    DopplerShift is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DopplerShift is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DopplerShift.  If not, see <http://www.gnu.org/licenses/>.
'''
from lxml import etree
from twisted.python import log
from dopplershift.core.containers.mediator import getMediator
from dopplershift.collector.exc import Http500, Http404, HttpCustom
import logging
from dopplershift.core.utils.xmlserializer import DSXMLSerializer
import traceback
logger = logging.getLogger(__name__)

class Render:
    _cond = None
    _auth_user = None
    def __init__(self, event_manager_id, request_id):
        self._em_id = event_manager_id
        self._request_id = request_id
        self.config = getMediator().get("AppConfig")
        
        
    def _getRequest(self):
        return getMediator().get('CollectorRequests').get(self._request_id)
    def _getEventManager(self):
        return getMediator().get("CollectorHandlers").get(self._em_id)
    
    def renderInternalServerError(self):
        request = self._getRequest()
        self._getEventManager().signal("StartRendering", False)
        request.setResponseCode(500)
        
        try:
            request.write(getMediator().get('ErrorRender').render(500))
            request.finish()
        except:
            print "request finish imposible"
            traceback.print_exc()
    def authResponse(self, answer):
        self._auth_user = answer
        try:
            self._auth_user = etree.fromstring(answer)
        except:
            return False
        return True
    def renderNotFoundError(self):
        request = self._getRequest()
        self._getEventManager().signal("StartRendering", False)
        request.setResponseCode(404)
        try:
            res = getMediator().get('ErrorRender').error(request, 404)
            if res is not None:
                request.write()
                request.finish()
        except:
            traceback.print_exc()
            print "request finish imposible"
    def setCondition(self, cond):
        self._condition = cond
    def callsProcessing(self, answer):
        try:
            self._callsProcessing(answer)
        except:
            log.err()
    def _callsProcessing(self, answer):
        material = {}
        renderer = self._condition.getRenderer()
        try:
            material = renderer.prepare(answer['responses'], self._condition.getCalls(), answer['matched_params'], self._auth_user, request=self._getRequest())
        except Http500:
            return renderer.error_render(self._getRequest(), 500)
        except Http404:
            return renderer.error_render(self._getRequest(), 404)
        except HttpCustom as e:
            return renderer.error(self._getRequest(), e._reason)
        if 'session' in material and len(material['session']) > 0:
            self.session(material['session'])
        if 'redirect' in material and material['redirect']:
            return self.redirect(material['redirect'])        
        return self.render(material['material'])
    def _parseResultSegment(self, data, node_id='node', err_except=None):
        try:
            d = etree.fromstring(data)
        except ValueError:
            if err_except != None:
                if err_except == '500':
                    raise Http500('Parsing of primary node %s not possible, raising Http500'%(node_id))
                elif err_except == '404':
                    raise Http404('Parsing of primary node %s not possible, but need raise Http404 by rule'%node_id)
            return False
        except:
            log.err()
            if err_except == '500':
                raise Http500('Parsing of primary node %s excepted. Out of rendering'%(node_id))
            return False
        return d
    def redirect(self, redirect):
        try:
            if self._condition.getContentType() == 'ololo/xml':
                return False
        except:
            log.err()
        request = self._getRequest()
        self._getEventManager().signal("StartRendering", None)
        request.redirect(str(redirect))

        try:
            request.finish()
        except:
            logger.debug("Except redirect, because user close connection")
        return True
    def session(self, session):
        '''
        '''
        request = self._getRequest()
        for k,v in session.iteritems():
            if v != None:
                request.addCookie(str(k),str(v), path='/')
            else:
                request.addCookie(str(k),str(v), path='/')
    def _checkRequestDebug(self, request):
        if self.config.get("PRODUCTION"): return True
        if 'debug' not in request.args:
            return False
        if '1' not in request.args['debug']:
            return False
        return True
    def render(self, material):
        '''
        '''
        request = self._getRequest()
        self._getEventManager().signal("StartRendering", None)
        ctype = self._getCtype()
        renderer = self._condition.getRenderer()
        renderer.render(request, material, self._condition.getTemplateName(), content_type=ctype)
        return

    def _processRedirect(self, node):
        if isinstance(node, bool):
            return
        for el in node.xpath('redirect/@url'):
            return el
        return False
    def _processSession(self, node, session):
        if isinstance(node, bool):
            return
        for el in node.xpath('session/item'):
            session[el.get('key')] = el.get('value')
        return session
    def _processContent(self, data, material, node_id='node'):
        content_cnt = 0
        for content in data.xpath('''content'''):
            content_cnt += 1
            node = etree.SubElement(material, node_id)
            node.append(content)
        return True
    def _getCtype(self):
        ctype = self._condition.getContentType()
        if ctype == None:
            ctype = 'text/html'
        return ctype
